package com.zdya.combatdocuments.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zdya.combatdocuments.component.CombatDocumentConfig;
import com.zdya.combatdocuments.constant.Constants;
import com.zdya.combatdocuments.entity.Network;
import com.zdya.combatdocuments.entity.NetworkUser;
import com.zdya.combatdocuments.entity.Node;
import com.zdya.combatdocuments.entity.User;
import com.zdya.combatdocuments.entity.vo.ResultEnum;
import com.zdya.combatdocuments.entity.vo.ResultVo;
import com.zdya.combatdocuments.entity.vo.Token;
import com.zdya.combatdocuments.entity.vo.UserLoginVo;
import com.zdya.combatdocuments.ethereum.EthChain;
import com.zdya.combatdocuments.exception.BusinessException;
import com.zdya.combatdocuments.mapper.NetworkMapper;
import com.zdya.combatdocuments.mapper.NetworkUserMapper;
import com.zdya.combatdocuments.mapper.UserMapper;
import com.zdya.combatdocuments.p2pNetwork.NodeUtil;
import com.zdya.combatdocuments.service.UserService;
import com.zdya.combatdocuments.util.*;
import io.jsonwebtoken.*;
import net.sourceforge.pinyin4j.PinyinHelper;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private JwtUitls jwtUitls;
    @Autowired
    NodeUtil nodeUtil;
    @Autowired
    NetworkMapper networkMapper;
    @Autowired
    NetworkUserMapper networkUserMapper;


    @Override
    public ResultVo<User> getDetails(String username) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, username);
        User userEntity = baseMapper.selectOne(queryWrapper);
        return ResultVoUtil.success(userEntity);
    }

    @Override
    public ResultVo<Object> updateUser(User userEntity) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        if (userEntity.getPassword() != null){
            wrapper.eq(User::getPassword, DigestUtils.md5DigestAsHex(userEntity.getOldPwd().getBytes()));
            wrapper.eq(User::getUsername, userEntity.getUsername());
            User user = baseMapper.selectOne(wrapper);
            if (!Objects.isNull(user)) {
                LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(User::getUsername, userEntity.getUsername());
                userEntity.setPassword(DigestUtils.md5DigestAsHex(userEntity.getPassword().getBytes()));
                baseMapper.update(userEntity, queryWrapper);
                return ResultVoUtil.success(ResultEnum.SUCCESS.getMessage());
            }
            return ResultVoUtil.error("原密码输入错误");
        }
        wrapper.eq(User::getId, userEntity.getId());
        try {
            baseMapper.update(userEntity,wrapper);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException("修改管理员名称错误");
        }
        return ResultVoUtil.success(ResultEnum.SUCCESS.getMessage());
    }

    @Override
    public ResultVo<LinkedHashMap<String, List<User>>> getUserAndName(Long id, String name) {
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.ne(User::getId, id);
        userLambdaQueryWrapper.ne(User::getUsername, "admin");
        userLambdaQueryWrapper.like(StringUtils.isNotEmpty(name), User::getName, name);
        List<User> userEntities = baseMapper.selectList(userLambdaQueryWrapper);
        List<String> collect = userEntities.stream().map(User::getName).collect(Collectors.toList());
        Map<String, List<User>> hashMap = new HashMap<>();
        StringBuilder stringBuilder = new StringBuilder();
        String[] strings1 = new String[]{
                "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
                , "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
        };
        if (!collect.isEmpty()) {
            String s = "";
            for (int i = 0; i < collect.size(); i++) {
                s = collect.get(i);
                char word = s.charAt(0);
                String substring = s.substring(0, 1);
                String[] strings = PinyinHelper.toHanyuPinyinStringArray(word);
                Iterator<String> iterator = hashMap.keySet().iterator();
                while (iterator.hasNext()) {
                    String key = iterator.next();
                    stringBuilder.append(key);
                }
                if (strings != null || Arrays.asList(strings1).contains(substring)) {
                    String s2 = "";
                    if (strings != null) {
                        char c = strings[0].charAt(0);
                        s2 = Character.toString(c).toUpperCase();
                    } else {
                        s2 = substring.toUpperCase();
                    }
                    if (hashMap.size() != 0) {
                        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
                        queryWrapper.eq(User::getName, s);
                        List<User> entityList1 = baseMapper.selectList(queryWrapper);
                        String s1 = stringBuilder.toString();
                        stringBuilder.delete(0, stringBuilder.length());
                        if (s1.contains(s2)) {
                            List<User> entityList = hashMap.get(s2);
                            List<User> entityList2 = baseMapper.selectList(queryWrapper);
                            if (!entityList.containsAll(entityList2)) {
                                List<User> userEntity = baseMapper.selectList(queryWrapper);
                                entityList.addAll(userEntity);
                                hashMap.put(s2, entityList);
                            } else {
                                hashMap.put(s2, entityList);
                            }
                        } else {
                            hashMap.put(s2, entityList1);
                        }
                    } else {
                        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
                        queryWrapper.eq(User::getName, s);
                        List<User> userEntity = baseMapper.selectList(queryWrapper);
                        hashMap.put(s2, userEntity);
                    }
                } else {
                    String s1 = stringBuilder.toString();
                    String s3 = "#";
                    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(User::getName, s);
                    List<User> userEntity = baseMapper.selectList(queryWrapper);
                    if (s1.contains(s3)) {
                        List<User> entityList = hashMap.get(s3);
                        List<User> entityList2 = baseMapper.selectList(queryWrapper);
                        if (!entityList.containsAll(entityList2)) {
                            List<User> userEntity1 = baseMapper.selectList(queryWrapper);
                            entityList.addAll(userEntity1);
                            hashMap.put(s3, entityList);
                        } else {
                            hashMap.put(s3, entityList);
                        }
                    } else {
                        hashMap.put(s3, userEntity);
                    }
                }
            }
        }
        ArrayList<String> list = new ArrayList<>();
        LinkedHashMap<String, List<User>> treeMap = new LinkedHashMap<>();
        Iterator<String> iterator = hashMap.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            if (!"#".equals(key)) {
                list.add(key);
            }
        }
        Collections.sort(list);
        for (String s : list) {
            treeMap.put(s, hashMap.get(s));
        }
//        List<User> users = hashMap.get("#");
//        if (users.size()!=0){
//            treeMap.put("#",hashMap.get("#"));
//        }
        treeMap.put("#", hashMap.get("#"));
        return ResultVoUtil.success(treeMap);
    }

    @Override
    public ResultVo<UserLoginVo> login(User userEntity) {
        if ("admin".equals(userEntity.getUsername())) {
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getUsername, userEntity.getUsername());
            String s = DigestUtils.md5DigestAsHex(userEntity.getPassword().getBytes());
            queryWrapper.eq(User::getPassword, s);
            User userOne = baseMapper.selectOne(queryWrapper);
            if (!Objects.isNull(userOne)) {
                userEntity.setStatus(1);
                userEntity.setPassword(s);
                baseMapper.update(userEntity, queryWrapper);
                String userId = userOne.getId().toString();
                String token = jwtUitls.createToken(userId, userOne.getUsername());
                UserLoginVo userLoginVo = new UserLoginVo(token, userOne);
                if (StringUtils.isNotEmpty(Token.map.get("token"))) {
                    Token.map.clear();
                    Token.map.put("token", token);
                } else {
                    Token.map.put("token", token);
                }
                return ResultVoUtil.success(userLoginVo);
            }
            return ResultVoUtil.error(ResultEnum.USER_ERROR.getMessage());
        } else {

            String osName = DmcUtils.getOSName();
            String decrypt = FileUtil.ReadTxt(userEntity.getUsername());
            if ("授权文件不存在".equals(decrypt)) {
                return ResultVoUtil.error("授权文件不存在");
            }
            JSONObject object = JSONObject.parseObject(decrypt);
            String mac = object.get("mac").toString();
            String username = object.get("username").toString();
            String cpu = object.get("cpu").toString();
            Map<String, String> allSn = SerialNumberUtil.getAllSn();
            String cpuid = allSn.get("cpuid");
            Long expirationTime = object.getLong("expirationTime");
            //long expirationTime = Long.parseLong(object.get("expirationTime").toString());
            LocalDate now = LocalDate.now();
            long time = Timestamp.valueOf(now.atStartOfDay()).getTime();
            if (time <= expirationTime) {
                if (osName.contains("windows")) {
                    try {
                        String WinMac = DmcUtils.getLocalMacAddress();
                        if (!(mac.equalsIgnoreCase(WinMac) && userEntity.getUsername().equalsIgnoreCase(username) && cpu.equals(cpuid)))
                            return ResultVoUtil.error(ResultEnum.AUTHORIZATION_DOCUMENT_ERROR.getMessage());
                    } catch (SocketException e) {
                        e.printStackTrace();
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                    }
                } else if (osName.contains("linux")) {
                    String LinuxMac = DmcUtils.getMAC_linux();
                    if (!(mac.equalsIgnoreCase(LinuxMac) && userEntity.getUsername().equalsIgnoreCase(username) && cpu.equals(cpuid)))
                        return ResultVoUtil.error(ResultEnum.AUTHORIZATION_DOCUMENT_ERROR.getMessage());
                }
                //重置清除数据状态
                nodeUtil.isClear = false;
                // if (username.equalsIgnoreCase(userEntity.getUsername()) && mac.equalsIgnoreCase(authorizationServiceOne.getMac())){
                LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(User::getUsername, userEntity.getUsername());
                User userEntity1 = baseMapper.selectOne(queryWrapper);
                if (Objects.isNull(userEntity1)) {
                    userEntity.setName(object.get("name").toString());
                    userEntity.setUsername(userEntity.getUsername());
                    userEntity.setTel(object.get("tel").toString());
                    userEntity.setElement(object.get("element").toString());
                    userEntity.setSeat(object.get("seat").toString());
                    userEntity.setIp(nodeUtil.getLocalIp());
                    userEntity.setPublicKey(object.get("publicKey").toString());
                    userEntity.setPrivateKey(object.get("privateKey").toString());
                    userEntity.setAddress(object.get("address").toString());
                    userEntity.setKeystore(object.get("keystore").toString());
                    userEntity.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
                    baseMapper.insert(userEntity);
                    nodeUtil.setLocalUser(userEntity);
                    userEntity.setStatus(1);
                    baseMapper.update(userEntity, queryWrapper);
                    String userId = userEntity.getId() + "";
                    String token = jwtUitls.createToken(userId, userEntity.getUsername());
                    UserLoginVo userLoginVo = new UserLoginVo(token, userEntity);
                    if (StringUtils.isNotEmpty(Token.map.get("token"))) {
                        Token.map.clear();
                        Token.map.put("token", token);
                    } else {
                        Token.map.put("token", token);
                    }
                    return ResultVoUtil.success(userLoginVo);
                } else {
                    User user = new User();
                    user.setName(object.get("name").toString());
                    user.setTel(object.get("tel").toString());
                    user.setElement(object.get("element").toString());
                    user.setSeat(object.get("seat").toString());
                    user.setIp(nodeUtil.getLocalIp());
                    user.setPublicKey(object.get("publicKey").toString());
                    user.setPrivateKey(object.get("privateKey").toString());
                    user.setAddress(object.get("address").toString());
                    user.setKeystore(object.get("keystore").toString());
                    if (!"".equals(userEntity1.getPassword())){
                        if (userEntity1.getPassword().equals(DigestUtils.md5DigestAsHex(userEntity.getPassword().getBytes()))) {
                            user.setStatus(1);
                            baseMapper.update(user, queryWrapper);
                            String userId = userEntity1.getId().toString();
                            String token = jwtUitls.createToken(userId, userEntity1.getUsername());
                            UserLoginVo userLoginVo = new UserLoginVo(token, userEntity1);
                            nodeUtil.setLocalUser(userEntity1);
                            if (StringUtils.isNotEmpty(Token.map.get("token"))) {
                                Token.map.clear();
                                Token.map.put("token", token);
                            } else {
                                Token.map.put("token", token);
                            }
                            return ResultVoUtil.success(userLoginVo);
                        }
                        return ResultVoUtil.error("密码错误");
                    }
                    user.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
                    user.setStatus(1);
                    baseMapper.update(user, queryWrapper);
                    String userId = userEntity1.getId().toString();
                    String token = jwtUitls.createToken(userId, userEntity1.getUsername());
                    UserLoginVo userLoginVo = new UserLoginVo(token, userEntity1);
                    nodeUtil.setLocalUser(userEntity1);
                    if (StringUtils.isNotEmpty(Token.map.get("token"))) {
                        Token.map.clear();
                        Token.map.put("token", token);
                    } else {
                        Token.map.put("token", token);
                    }
                    return ResultVoUtil.success(userLoginVo);
                }
            }
            return ResultVoUtil.error("授权文件过期");
        }

    }

    @Override
    public ResultVo upload(Long id, MultipartFile file, HttpServletRequest request) {
        try {
            File file1 = new File(CombatDocumentConfig.getProfile() + Constants.PIC_PREFIX);
            if (!file1.exists()) {
                file1.mkdirs();
            }
            String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
            String newFileName = UUID.randomUUID().toString().replace("-", "") + suffix;

            file.transferTo(new File(CombatDocumentConfig.getProfile() + Constants.PIC_PREFIX + newFileName));

            String url = request.getScheme() + "://" + nodeUtil.getLocalIp() + ":" + request.getServerPort() + Constants.RESOURCE_PREFIX + Constants.PIC_PREFIX + newFileName;
            User user = new User();
            user.setAvatarUrl(url);
            LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
            userLambdaQueryWrapper.eq(User::getId, id);
            baseMapper.update(user, userLambdaQueryWrapper);
            return ResultVoUtil.success(user);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ResultVoUtil.error(ResultEnum.UPLOAD_ERROT.getMessage());
    }

    @Override
    public ResultVo saveUser(User user) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, user.getUsername());
        User selectOne = baseMapper.selectOne(queryWrapper);
        if (Objects.isNull(selectOne)) {
            baseMapper.insert(user);
            return ResultVoUtil.success(ResultEnum.SUCCESS.getMessage());
        }
        return ResultVoUtil.error(ResultEnum.USER_FRIEND_EXIST.getMessage());
    }

    @Override
    public ResultVo logout() {
        log.debug("**************退出登录*************");
        String token = "123";
        if (StringUtils.isNotEmpty(token)) {
            try {
//                Claims claims = null;
//                claims = Jwts.parser().setSigningKey("12345678").parseClaimsJws(token).getBody();

                //从token中获取用户id，查询该Id的用户是否存在，存在则token验证通过

                User localUser = nodeUtil.getLocalUser();
                if (localUser.getId() == null) {
                    return ResultVoUtil.success();
                }

                Long id = localUser.getId();
                User user = baseMapper.selectById(id);
                user.setStatus(0);
                LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
                userLambdaQueryWrapper.eq(User::getId, id);
                baseMapper.update(user, userLambdaQueryWrapper);

                //关闭网络&&网络用户表

//                LambdaQueryWrapper<Network> queryWrapper = new LambdaQueryWrapper<>();
//                queryWrapper.eq(Network::getStatus, 0);
//                List<Network> networks = networkMapper.selectList(queryWrapper);
//                for (Network network : networks) {
//                    network.setStatus(1);
//                    networkMapper.updateById(network);
//                    NetworkUser networkUser = networkUserMapper.selectOne(new QueryWrapper<NetworkUser>().eq("network_id", network.getId()).eq("user_id", nodeUtil.getLocalUser().getId()));
//                    networkUser.setStatus(1);
//                    networkUserMapper.updateById(networkUser);
//                }

                for (Node node : nodeUtil.getNodeList()) {
                    node.getWebSocket().close();
                }
                //Network network = networkMapper.selectById(nodeUtil.getNetworkId());


                nodeUtil.getNodeList().clear();
                nodeUtil.getIdToIpList().clear();
                nodeUtil.getUserList().clear();
                nodeUtil.getIp_keyList().clear();
                Token.map.clear();
//                log.debug("**************停止挖矿*************");
//                EthChain.stopMine();
                //关闭区块链
                log.debug("**************关闭本机区块链节点*************");
                KillPortUtils.start();

                return ResultVoUtil.success(ResultEnum.SUCCESS.getMessage());
            } catch (ExpiredJwtException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return ResultVoUtil.error("未携带token");
    }

    @Override
    public ResultVo findMacAndCpu() {
        String osName = DmcUtils.getOSName();
        osName = osName.toUpperCase();
        Map<String, String> map = new HashMap<>();
        Map<String, String> allSn = SerialNumberUtil.getAllSn();
        String cpuid = allSn.get("cpuid");
        if ("LINUX".equals(osName)) {
            String mac_linux = DmcUtils.getMAC_linux();
            map.put("mac", mac_linux);
            map.put("cpu", cpuid);
            return ResultVoUtil.success(map);
        } else {
            try {
                String localMacAddress = DmcUtils.getLocalMacAddress();
                map.put("mac", localMacAddress);
                map.put("cpu", cpuid);
                return ResultVoUtil.success(map);
            } catch (SocketException e) {
                e.printStackTrace();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
        }
        return ResultVoUtil.error("获取本机Mac地址和Cpu错误");
    }


    @Override
    public ResultVo uploadFile(MultipartFile file) {
        //获取原始文件名
        String fileName = file.getOriginalFilename();
        String url = CombatDocumentConfig.getProfile() + Constants.AUTHOR_PREFIX;
        //创建一个目录对象
        File dir = new File(url);
        //判断当前目录是否存在
        if (!dir.exists()) {
            //目录不存在，需要创建
            dir.mkdirs();
        }

        try {
            //将临时文件转存到指定位置
            file.transferTo(new File(url + fileName));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ResultVoUtil.success("上传文件成功");
    }
}
